#include <dcont/catch.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

fresume_t jp;
fresume_t jp1;
word_t flag = 0;

static inline void test_candy1(){
	if (flag != 0){
		printf("long jmp\n");
		LONGJMP(&jp, 1);
	}
}

static inline void test_candy(){
	// word_t cnt;
	if(0 == SETJMP(&jp)){
		printf("init jump\n");
		flag = 1;
	}else{
		printf("oop, back to this point\n");
		flag = 0;
	}
	
	test_candy1();
}




fresume_t buf;

fresume_t buf1;

word_t cont_test1(word_t arg){
	SETJMP(&buf1);
	printf("cont_test1 running...%p\n", (void *)arg);
	LONGJMP(&buf, 1);
	UNREACHABLE();
}
word_t ret_cnt = 0; /* 需要是volatile, 否则clang运行可能会出错?? */
void test_fastcont(){
	void *stk = aligned_alloc(4096, 8192); 
	// word_t cnt = 0; /* 需要是volatile, 否则clang运行可能会出错?? clang语义是对的，longjmp的时候状态应该不变 */

	if (SETJMP(&buf) == 0){
		printf("save completed\n");
		setstack_exec(cont_test1, ret_cnt, ((paddr_t)stk + 8192 - HDEF_STK_ALIGN_BYTES));
	}else{
		printf("back\n");
		if (ret_cnt++ < 10){
			setstack_exec(cont_test1, ret_cnt, ((paddr_t)stk + 8192 - HDEF_STK_ALIGN_BYTES));
			// fresume(&buf1, 1);
		}
	}

	printf("run completed\n");
}

/* 问题出在读写resume指针必须，c和clang静态分析无法分析得出 */
TLS_INITIAL fresume_t *pres;
TLS_INITIAL fresume_t *rout_res;

NORETURN word_t rout_test(word_t arg){
	fresume_t res;
	// printf("running rout\n");
	word_t * p = (word_t *)arg;
	if(SETJMP(&res) == 0){
		rout_res = &res;
		LONGJMP(pres, 1);
	}else{
		// *p = *p + 1;
		atm_st(p, *p+1);
		printf("yield back %lu\n", (ulong_t)atm_ld(p));
	}

	LONGJMP(pres, 1);
}

void test_cont(){
	void *stk = aligned_alloc(4096, 8192); 

	fresume_t res;
	word_t volatile ret = 41;
	pres = &res;
	// atm_st(&pres, &res);
	if (SETJMP(&res) == 0){
		setstack_exec(rout_test, (word_t)&ret, ((size_t)stk + 8192));
	}
	else{
		printf("rout yield\n");
	}
	// ret = 41;
	printf("ready to resume \n");
	fresume_t res1;
	if(SETJMP(&res1) == 0){
		pres = &res1;
		LONGJMP(rout_res, 1);
	}else{
		printf("rout return %lu\n", (ulong_t)ret);
		assert(ret == 42);
	}
	printf("run completed\n");
}


TLS_INITIAL try_exc_t *__try_catch_buf;			 
DEF_UTRYCATCH(tcbuf, __try_catch_buf)

#define ERROR   (-1)
#define ERROR1  (-2)
int test_func111(int arg){
	if (arg == 0) RAISE(ERROR);
	printf("check func ok\n");
	return 0;
}

int test_func112(int arg){
	if (arg == 1) RAISE(ERROR1);
	printf("check func ok\n");
	return 0;
}


void test_trycatch(){
	DECL_TRYCATCH;

	TRY {
		int ret = test_func111(1);
		assert(ret == 0);
		test_func111(0);
	} CATCH(ERROR){
		printf("[oops!] you passed zero\n");
	}

	TRY{
		int ret = test_func112(0);
		assert(ret == 0);
		test_func112(1);
	} CATCH(ERROR){
		printf("[oops!] you passed zero\n");
	} CATCH(ERROR1){
		printf("[oops!] you passed 1\n");
	}
	__try_catch_buf = NULL_PTR;
}

int main(){
	test_candy();
	test_fastcont();
	test_trycatch();
	test_cont();
	return 0;
}
